/**
 * ChartController
 * @class
 * @property {ChartDataProvider} cp - dataprovider for charting
 * @property {PilotChart} pilotChart - charting view
 * 
 */
function ChartController() {


    this.cp =  null;

    this.pilotChart = null;
    

    this.errorMsgs = [];

    this.logger = new PilotLog(this.errorMsgs);
}

/**
 * @param {PilotChart} pilotChart
 * 
 * @param {ChartDataProvider} dataProvider
 */
ChartController.prototype.init = function(pilotChart,dataProvider){
    var self = this;
    this.pilotChart = pilotChart;
    this.cp = dataProvider;
    this.cp.initWithCallbacks({
        onInitChart:(chartConfig)=> {
            this.pilotChart.initChartWithConfig(chartConfig);
        },
        onChartConnectionOpened:(chartConfig,connection)=>{
            this.sendConfig(chartConfig,connection);
        },
    });


    this.pilotChart.setPilotChartEvent({
        requestMoreDataEvent :(startTime,endTime)=>{
            //TODO request more data to server
            this.getMoreData(startTime,endTime);
        },
        dataIntervalChangedEvent:(sampleInterval,maxDataPoint) =>{
            //TODO getNewData
            this.changeDataInterval(sampleInterval,maxDataPoint);
        }
});
    

}


/**
 * @description send config to connection , and get data back
 * @param {ConfigRequestOptions} chartConfig
 * @param {ChartConnection}  connection
 */
ChartController.prototype.sendConfig = function(chartConfig,connection){
    var seriesData = {};
    var subscription = this.cp.configAndGetData(chartConfig,{
        onStart:()=>{
            this.pilotChart.showLoading("Loading Data...");
        },
        onEnd:()=>{
            this.pilotChart.processQueryData(seriesData,false);
            this.pilotChart.hideLoading();
        },
        onResponse:(payload)=>{
            this._processQueryData(payload,seriesData);
        },
        onEvent:(payload)=>{
            this._processSubscribeData(payload);
        },
        onError:(e)=>{
            this.pilotChart.hideLoading();
            this.logger.error(e.seriesName,e.errorCode,e.errorMsg);
        }
    },connection);

    return subscription;

}

/**
 * @description get more data from server
 * @param {number} startTime
 * @param {number} endTime 
 */
ChartController.prototype.getMoreData = function(startTime,endTime,callback){
    if(isValued(callback)){
        callback();
    }
    var seriesData = {};
    this.pilotChart.showLoading("loading more data ...");
    var subscription = this.cp.getMoreData({
        startTime:startTime,
        endTime:endTime,
        requestId:"eabc"
    },{
        onStart:()=>{
            // this.pilotChart.showLoading("get more data ...");
        },
        onEnd:()=>{
            this.pilotChart.processQueryData(seriesData,true);
            this.pilotChart.hideLoading();
        },
        onError:()=>{
            this.pilotChart.hideLoading();
        },
        onResponse:(payload)=>{
            this._processQueryData(payload,seriesData);
        }
    });
    return subscription;
}

/**
 * @description changeDataInterval
 * @param {number} sampleInterval -if <= 0, means it's tickdata
 * @param {number} [maxDataPoint] -this is only for tickData
 * 
 */
ChartController.prototype.changeDataInterval =function(sampleInterval,maxDataPoint,requestId){
    // clear data
    this.pilotChart.showLoading("loading data ...");
    var seriesData = {};
    var subscription = this.cp.getNewData({
        sampleInterval:sampleInterval,
        maxDataPoint:maxDataPoint,
        requestId:requestId
    },{
        onStart:()=>{
            // this.pilotChart.showLoading("get more data ...");
        },
        onEnd:()=>{
            this.pilotChart.processQueryData(seriesData,false);
            this.pilotChart.hideLoading();
        },
        onResponse:(payload)=>{
            this._processQueryData(payload,seriesData);
        },
        onEvent:(payload)=>{
            this._processSubscribeData(payload);
        },
        onError:(e)=>{
            this.pilotChart.hideLoading();
        }
    });
    return subscription;
}


ChartController.prototype._processSubscribeData = function(seriesData){
    var self = this;
    var seriesName = seriesData.seriesName;
    var convertData = this._convertData(seriesData);
    if(convertData.length>0){
        convertData.forEach(d=>{
            self.pilotChart.processSubscribeData(seriesName,d);
        })
    }
}


ChartController.prototype._processQueryData = function (seriesData,cachedSeriesData) {
    var self = this;
    var seriesName = seriesData.seriesName;
    
    if(!isValued(cachedSeriesData[seriesName])){
        cachedSeriesData[seriesName] = [];
    }
    var convertData = self._convertData(seriesData);
    if(convertData.length>0){
        cachedSeriesData[seriesName].push(...convertData);
    }
}

ChartDataProvider.prototype._convertData = function (seriesData) {
    var dataType = seriesData.dataType;
    if(seriesData.data && seriesData.data.length> 0){
        if(this.isSampleData(dataType)){
            return this._convertDataToOHLC(seriesData);
        }
        return this._convertDataToLine(seriesData);
    }

    return [];

}

ChartController.prototype.isSampleData = function(dataType){
    if(dataType === "Sampled"){
        return true;
    }
    return false;
}

ChartController.prototype._convertDataToOHLC = function (seriesData) {
    var convertedData = [];
    for (var index = 0; index < seriesData.data.length; ++index) {
      var point = seriesData.data[index];
      convertedData.push([
        point.x,
        point.open,
        point.high,
        point.low,
        point.close
      ]);
    }
    return convertedData;
}

ChartController.prototype._convertDataToLine = function (seriesData) {
    var self = this;
    var convertedData = [];
    var addPoint;
    for (var index = 0; index < seriesData.data.length; index++) {
      addPoint = true;
      var point = seriesData.data[index];
      if ( isNaN( point.x ) ) {
        console.log("Invalid point x value: ", point);
        continue;
      }

      //null points are hidden
      if ( "y" in point == false ) {
          point.y = null;
      } else if ( isNaN(point.y)) {
        console.log("Invalid point y value: ", point);
        continue;
      }
      var xValue;
      if (seriesData.fixedXValue && seriesData.fixedXValue != null) {
        xValue = seriesData.fixedXValue;
      } else {
        xValue = point.x;
      }
      //TODO businessHours
      if (seriesData.timeSeries && !isWithinBusinessHours(xValue)) {
        addPoint = false;
      }
      if (addPoint) {
        var pointAsArray = [xValue, point.y];
        convertedData.push(pointAsArray);
      }

    }
    return convertedData;
    
}



function groupClick(el){
    console.log("groupClick",el);
}



function PilotLog(errorMsgs){
    this.errorMsgs = errorMsgs || [];
    this.error = function(){
        this.errorMsgs.push(arguments);
        console.error.apply( this, arguments);
    }
    this.info = console.info;

    this.log = console.log;

    this.warn = console.log;

    this.debug = console.debug;
}
